﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Collections;

namespace Microsoft.Office.OneNote
{
    internal sealed class OneNoteObjectCollectionDebugView<T>
    {
        private readonly ICollection<T> _collection;

        public OneNoteObjectCollectionDebugView(ICollection<T> collection)
        {
            _collection = collection;
        }

        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        public T[] Items
        {
            get
            {
                T[] array = new T[_collection.Count];
                _collection.CopyTo(array, 0);
                return array;
            }
        }
    }

    [DebuggerDisplay("Count = {Count}")]
    [DebuggerTypeProxy(typeof(OneNoteObjectCollectionDebugView<>))]
    public sealed class OneNoteObjectCollection<T> : IList<T>, IList
        where T : OneNoteObjectWithIdentity
    {
        private OneNoteObjectStorageBase _storage;
        private List<T> _innerList;

        internal OneNoteObjectCollection(OneNoteObjectStorageBase storage)
        {
            _storage = storage;
            _storage.Updated += OnStorageUpdated;
            
            Update();
        }

        internal void Update()
        {
            if (_storage.IsInvalid)
            {
                _storage.Updated -= OnStorageUpdated;
                
                _innerList = null;
                _storage = null;

                return;
            }

            _innerList = new List<T>(_storage.OfType<T>());
        }

        public T Last
        {
            get
            {
                CheckValid();

                if (Count > 0)
                {
                    return _innerList[Count - 1];
                }

                return null;
            }
        }

        public T First
        {
            get
            {
                CheckValid();

                if (Count > 0)
                {
                    return _innerList[0];
                }

                return null;
            }
        }

        #region IList<T> Members

        public int IndexOf(T item)
        {
            CheckValid();
            return _innerList.IndexOf(item);
        }

        void IList<T>.Insert(int index, T item)
        {
            throw ReadOnly();
        }

        void IList<T>.RemoveAt(int index)
        {
            throw ReadOnly();
        }

        public T this[int index]
        {
            get { CheckValid(); return _innerList[index]; }
            set { throw ReadOnly(); }
        }

        #endregion

        #region IList Members

        int IList.Add(object value)
        {
            throw ReadOnly();
        }

        void IList.Clear()
        {
            throw ReadOnly();
        }

        bool IList.Contains(object value)
        {
            return Contains((T)(value));
        }

        int IList.IndexOf(object value)
        {
            return IndexOf((T)(value));
        }

        void IList.Insert(int index, object value)
        {
            throw ReadOnly();
        }

        bool IList.IsFixedSize
        {
            get { return false; }
        }

        bool IList.IsReadOnly
        {
            get { return true; }
        }

        void IList.Remove(object value)
        {
            throw ReadOnly();
        }

        void IList.RemoveAt(int index)
        {
            throw ReadOnly();
        }

        object IList.this[int index]
        {
            get
            {
                return this[index];
            }
            set
            {
                throw ReadOnly();
            }
        }

        #endregion

        #region ICollection<T> Members

        void ICollection<T>.Add(T item)
        {
            throw ReadOnly();
        }

        void ICollection<T>.Clear()
        {
            throw ReadOnly();
        }

        public bool Contains(T item)
        {
            CheckValid();
            return _innerList.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            CheckValid();
            _innerList.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get
            {
                CheckValid();
                return _innerList.Count;
            }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        bool ICollection<T>.Remove(T item)
        {
            throw ReadOnly();
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            CheckValid();
            return _innerList.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            CheckValid();
            return _innerList.GetEnumerator();
        }

        #endregion

        private void OnStorageUpdated(object sender, EventArgs e)
        {
            Update();
        }

        private void CheckValid()
        {
            if (_storage == null)
            {
                throw FrameworkExceptions.ObjectInvalid();
            }
        }

        private static Exception ReadOnly()
        {
            return new NotSupportedException();
        }

        #region ICollection Members

        void ICollection.CopyTo(Array array, int index)
        {
            CopyTo((T[])(array), index);
        }

        bool ICollection.IsSynchronized
        {
            get { return false; }
        }

        object ICollection.SyncRoot
        {
            get { return null; }
        }

        #endregion
    }
}
